<?php

declare(strict_types=1);

namespace Plugin\Attractions\HaiKang\Service;

use App\Exception\BusinessException;
use App\Http\Common\ResultCode;
use Common\Common;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Di\Annotation\Inject;
use Plugin\Attractions\HaiKang\Common\HKAPI;
use Plugin\Attractions\HaiKang\Repository\DeviceChannelRepository;
use Plugin\Attractions\HaiKang\Repository\DeviceGroupRepository;
use Plugin\Attractions\HaiKang\Repository\DeviceRepsitory;

class HKDeviceService
{
    #[Inject()]
    private DeviceRepsitory $deviceRepository;
    #[Inject()]
    private DeviceGroupRepository $deviceGroupRepository;
    #[Inject()]
    private DeviceChannelRepository $deviceChannelRepository;
    #[Inject()]
    private HKAPI $api;

    public function groupList(array $params)
    {
        return $this->deviceGroupRepository->list($params);
    }

    public function deviceList(array $params)
    {
        return $this->deviceRepository->list($params);
    }

    public function syncGroups(): array
    {
        try {
            $groupList = $this->api->groupsList();
            if (!empty($groupList)) {
                $dbGroupList = $this->deviceGroupRepository->list()->keyBy('group_id')->toArray();
                foreach ($groupList as $group) {
                    $data = [
                        'group_id' => $group['groupId'],
                        'group_name' => $group['groupName'],
                        'group_no' => $group['groupNo'],
                        'parent_id' => $group['parentId']
                    ];
                    if (isset($dbGroupList[$group['groupId']]) && $data != $dbGroupList[$group['groupId']]) {
                        $this->deviceGroupRepository->updateById($group['groupId'], $data);
                        $dbGroupList[$group['groupId']] = $data;
                    } else if (!isset($dbGroupList[$group['groupId']])) {
                        $this->deviceGroupRepository->create($data);
                        $dbGroupList[$group['groupId']] = $data;
                    }
                }
                return $dbGroupList;
            }
            return $this->deviceGroupRepository->list()->keyBy('group_id')->toArray();
        } catch (BusinessException $e) {
            throw $e;
        } catch (\Exception $e) {
            Common::log(__CLASS__, '海康同步分组失败 message:' . $e->getMessage() . ' line:' . $e->getLine() . ' ', 'error');
            throw new BusinessException(ResultCode::FAIL);
        }
    }

    public function syncDevices($params): array
    {
        try {
            if (Coroutine::inCoroutine()) {
                $dbDeviceList = $this->deviceRepository->list([])->keyBy('device_id')->toArray();
                $groupList = $this->deviceGroupRepository->list([])->keyBy('group_id')->toArray();
                foreach ($groupList as $groupID => $group) {
                    for ($page = 1;; $page++) {
                        $response = $this->api
                            ->devicesList(['group_no' => $group['group_no'], 'page' => $page]);
                        if (empty($response['rows'])) {
                            break;
                        }
                        foreach ($response['rows'] as $device) {
                            $data = [
                                'device_id' => $device['deviceId'],
                                'device_model' => $device['deviceModel'],
                                'device_name' => $device['deviceName'],
                                'device_serial' => $device['deviceSerial'],
                                'device_status' => $device['deviceStatus'],
                                'group_id' => $device['groupId'],
                                'is_encrypt' => $device['isEncrypt'],
                                'device_version' => $device['deviceVersion'],
                            ];
                            if (isset($dbDeviceList[$data['device_id']]) && $dbDeviceList[$data['device_id']] !== $data) {
                                $this->deviceRepository->updateById($data['device_id'], $data);
                                $dbDeviceList[$data['device_id']] = $data;
                            } else if (!isset($dbDeviceList[$data['device_id']])) {
                                $this->deviceRepository->create($data);
                                $newDeviceSerial[] = $device['deviceSerial'];
                                $dbDeviceList[$data['device_id']] = $data;
                            }
                        }
                        if (count($response['rows']) == $response['total']) {
                            break;
                        }
                    }
                    if (Coroutine::inCoroutine()) {
                        Coroutine::sleep(2);
                    }
                }
            } else {
                $dbDeviceList = $this->deviceRepository->list($params)->keyBy('device_id')->toArray();
                foreach ($dbDeviceList as $deviceID => $device) {
                    $response = $this->api->deviceInfo(['deviceSerial' => $device['device_serial']]);
                    if ($dbDeviceList[$response['device_id']] !== $response) {
                        $this->deviceRepository->updateById($response['device_id'], $response);
                        $dbDeviceList[$response['device_id']] = $response;
                    }
                }
            }

            if (isset($newDeviceSerial)) {
                Coroutine::create(function () use ($newDeviceSerial) {
                    $this->syncChannels(['deviceSerial' => $newDeviceSerial]);
                });
            }
            return $dbDeviceList;
        } catch (BusinessException $e) {
            throw $e;
        } catch (\Exception $e) {
            Common::log(__CLASS__, '海康同步设备失败 message:' . $e->getMessage() . ' line:' . $e->getLine() . ' ', 'error');
            throw new BusinessException(ResultCode::FAIL);
        }
    }

    public function syncChannels($params): array
    {
        try {
            $deviceList = $this->deviceRepository
                ->list($params)->keyBy('device_id')->toArray();
            $dbChannelList = $this->deviceChannelRepository
                ->list(['deviceSerial' => array_column($deviceList, 'device_serial')])
                ->keyBy('device_serial')->toArray();

            foreach ($deviceList as $deviceID => $device) {
                $deviceSerial = $device['device_serial'];
                for ($page = 1;; $page++) {
                    $response = $this->api->deviceChannelList([
                        'device_serial' => $deviceSerial,
                        'page' => $page,
                    ]);
                    if (empty($response['rows'])) {
                        break;
                    }
                    foreach ($response['rows'] as $channel) {
                        $data = [
                            'device_serial' => $channel['deviceSerial'],
                            'channel_id' => $channel['channelId'],
                            'channel_name' => $channel['channelName'],
                            'channel_no' => $channel['channelNo'],
                            'channel_status' => $channel['channelStatus'],
                            'channel_type' => $channel['channelType'],
                            'is_use' => $channel['isUse'],
                            'ipc_serial' => $channel['ipcSerial'],
                            'child_device_model' => $channel['childDeviceModel'],
                        ];
                        if (isset($dbChannelList[$channel['deviceSerial']]) && $data != $dbChannelList[$channel['deviceSerial']]) {
                            $this->deviceChannelRepository->updateById($channel['deviceSerial'], $data);
                            $dbChannelList[$channel['deviceSerial']] = $data;
                        } else if (!isset($dbChannelList[$channel['deviceSerial']])) {
                            $this->deviceChannelRepository->create($data);
                            $dbChannelList[$channel['deviceSerial']] = $data;
                        }
                    }
                    if (count($response['rows']) == $response['total']) {
                        break;
                    }
                }
                if (Coroutine::inCoroutine()) {
                    Coroutine::sleep(2);
                }
            }
            return $dbChannelList;
        } catch (BusinessException $e) {
            throw $e;
        } catch (\Exception $e) {
            Common::log(__CLASS__, '海康同步通道失败 message:' . $e->getMessage() . ' line:' . $e->getLine() . ' ', 'error');
            throw new BusinessException(ResultCode::FAIL);
        }
    }
}
